using DocumentFormat.OpenXml.ExtendedProperties;
using LF.Application.Extend;
using LF.Common;
using LF.Domain.Entities;
using LF.Domain.Services;
using LF.Shared.Dtos.Input;
using LF.Shared.Dtos.Out;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Distributed;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using Volo.Abp.ObjectMapping;
using Volo.Abp.Users;

namespace LF.Application.Services.Iml
{
    [Authorize]
    [ApiExplorerSettings(GroupName = SwaggerGroup.Sys)]
    public class AccountService : BaseService, IAccountService
    {
        private readonly IMenuManagerService _menuManager;
        private readonly IHttpContextAccessor _httpContext;
        private readonly IDistributedCache _cache;
        private readonly IUserManagerService _userManager;
        private readonly Random _random = new Random();

        public AccountService(
            IMenuManagerService menuManager,
            IObjectMapper<LFModule> mapper,
            IGlobalManagerService globalManager,
            IHttpContextAccessor httpContext,
            IDistributedCache cache,
            IUserManagerService userManager) : base(mapper, globalManager)
        {
            _menuManager = menuManager;
            _httpContext = httpContext;
            _cache = cache;
            _userManager = userManager;
        }

        /// <summary>
        /// 获取当前用户菜单
        /// </summary>
        /// <returns>菜单列表</returns>
        public Result<List<AccountMenus>> GetMenus()
        {
            try
            {
                var userId = _httpContext.HttpContext.User.GetUserId();
                if (!userId.HasValue)
                {
                    return Error<List<AccountMenus>>("未登录用户");
                }

                // 获取用户的菜单树
                var menuEntities = _menuManager.GetUserMenuTree(userId.Value);
                if (menuEntities == null || !menuEntities.Any())
                {
                    return Ok(new List<AccountMenus>());
                }

                // 将Menu实体转换为AccountMenus DTO
                var menuDtos = ConvertToAccountMenus(menuEntities);
                return Ok(menuDtos);
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "获取用户菜单失败");
                return Error<List<AccountMenus>>("获取菜单失败");
            }
        }

        /// <summary>
        /// 获取账号权限
        /// </summary>
        public Result<List<string>> GetPermissions()
        {
            try
            {
                var userId = _httpContext.HttpContext.User.GetUserId();
                if (!userId.HasValue)
                {
                    return Error<List<string>>("未登录用户");
                }

                // 获取用户的权限编码
                var permissionCodes = _menuManager.GetPermissionCodes(userId.Value);
                return Ok(permissionCodes);
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "获取用户权限失败");
                return Error<List<string>>("获取权限失败");
            }
        }

        /// <summary>
        /// 登出
        /// </summary>
        public Result Logout()
        {
            try
            {
                // 由于JWT是无状态的，服务端不需要进行特殊处理
                // 客户端会删除本地存储的Token
                return Ok("登出成功");
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "登出失败");
                return Error("登出失败");
            }
        }

        /// <summary>
        /// 生成验证码
        /// </summary>
        /// <returns>验证码图片</returns>
        [AllowAnonymous]
        public FileContentResult GetCaptcha()
        {
            try
            {
                // 生成随机验证码
                string captchaCode = GenerateRandomCode(4);
                
                // 生成验证码图片
                byte[] captchaImage = GenerateCaptchaImage(captchaCode, 120, 40);
                
                // 获取客户端IP和其他信息，用作缓存键的一部分
                var clientIp = _httpContext.HttpContext.Connection.RemoteIpAddress?.ToString() ?? "unknown";
                var userAgent = _httpContext.HttpContext.Request.Headers["User-Agent"].ToString();
                
                // 生成唯一的缓存键
                var cacheKey = GenerateCacheKey(clientIp, userAgent);
                
                // 将验证码存入缓存，设置5分钟过期
                _cache.SetString(cacheKey, captchaCode, new DistributedCacheEntryOptions
                {
                    AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5)
                });
                
                return new FileContentResult(captchaImage, "image/png");
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "生成验证码失败");
                return new FileContentResult(new byte[0], "image/png");
            }
        }

        /// <summary>
        /// 验证验证码
        /// </summary>
        /// <param name="captchaInput">验证码输入</param>
        /// <returns>验证结果</returns>
        [AllowAnonymous]
        public Result VerifyCaptcha(CaptchaInput captchaInput)
        {
            try
            {
                if (string.IsNullOrEmpty(captchaInput.Code))
                {
                    return Error("验证码不能为空");
                }
                
                // 获取客户端IP和其他信息，用作缓存键的一部分
                var clientIp = _httpContext.HttpContext.Connection.RemoteIpAddress?.ToString() ?? "unknown";
                var userAgent = _httpContext.HttpContext.Request.Headers["User-Agent"].ToString();
                
                // 生成唯一的缓存键
                var cacheKey = GenerateCacheKey(clientIp, userAgent);
                
                // 从缓存中获取验证码
                var storedCaptcha = _cache.GetString(cacheKey);
                
                if (string.IsNullOrEmpty(storedCaptcha))
                {
                    return Error("验证码已过期，请重新获取");
                }
                
                // 比较验证码，忽略大小写
                if (storedCaptcha.Equals(captchaInput.Code, StringComparison.OrdinalIgnoreCase))
                {
                    // 验证成功后，清除缓存中的验证码
                    _cache.Remove(cacheKey);
                    return Ok("验证码验证成功");
                }
                
                return Error("验证码错误");
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "验证码校验失败");
                return Error("验证码校验失败");
            }
        }

        /// <summary>
        /// 通过openid检查用户是否存在
        /// </summary>
        /// <param name="openId">微信openid</param>
        /// <returns>用户是否存在</returns>
        [AllowAnonymous]
        public Result<bool> CheckUser(string openId)
        {
            try
            {
                if (string.IsNullOrEmpty(openId))
                {
                    return Error<bool>("openId不能为空");
                }

                // 通过openId查询用户
                var user = _userManager.GetUserByOpenId(openId);
                var exists = user != null && !user.IsDelete && user.Active;
                
                return Ok(exists);
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "检查用户失败，openId: {OpenId}", openId);
                return Error<bool>("检查用户失败");
            }
        }


        [AllowAnonymous]
        public Result Register(UserRegister cust)
        {
            if (cust.OpenId.IsNullOrEmpty()
                || cust.Mobile.IsNullOrEmpty()
                || cust.WeixinName.IsNullOrEmpty())
            {
                return Error("注册信息不完整!");
            }
            var user = _userManager.GetUserByOpenId(cust.OpenId);
            if (user!=null&&user.Mobile==cust.Mobile)
            {
                return Error("该用户信息，已注册!");
            }
            // 根据手机号查找用户，使用 LINQ 查询
            var where = PredicateBuilder.New<User>(true);
            if (!string.IsNullOrEmpty(cust.Mobile))
            {

                where = where.And(p => !p.IsDelete && p.Mobile == cust.Mobile);
            }

            var olduser = _globalManager.Get<User>(where);
            olduser.OpenId = cust.OpenId;
            olduser.Avatar = cust.Avatar;
            olduser.WeixinName = cust.WeixinName;
            _globalManager.Update(olduser);
            return Ok();
        }



        #region 验证码生成辅助方法

        /// <summary>
        /// 生成缓存键
        /// </summary>
        private string GenerateCacheKey(string clientIp, string userAgent)
        {
            // 使用IP和User-Agent的一部分信息生成唯一的缓存键
            var input = $"{clientIp}_{userAgent.Substring(0, Math.Min(userAgent.Length, 50))}";
            
            using (var md5 = MD5.Create())
            {
                var inputBytes = Encoding.UTF8.GetBytes(input);
                var hashBytes = md5.ComputeHash(inputBytes);
                
                // 将字节数组转换为十六进制字符串
                var sb = new StringBuilder();
                for (var i = 0; i < hashBytes.Length; i++)
                {
                    sb.Append(hashBytes[i].ToString("x2"));
                }
                
                return $"Captcha:{sb}";
            }
        }
        
        /// <summary>
        /// 生成随机验证码
        /// </summary>
        /// <param name="length">验证码长度</param>
        /// <returns>随机验证码</returns>
        private string GenerateRandomCode(int length)
        {
            const string chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
            return new string(Enumerable.Repeat(chars, length)
                .Select(s => s[_random.Next(s.Length)]).ToArray());
        }

        /// <summary>
        /// 生成验证码图片
        /// </summary>
        /// <param name="code">验证码文本</param>
        /// <param name="width">图片宽度</param>
        /// <param name="height">图片高度</param>
        /// <returns>验证码图片字节数组</returns>
        private byte[] GenerateCaptchaImage(string code, int width, int height)
        {
            using var surface = SKSurface.Create(new SKImageInfo(width, height));
            var canvas = surface.Canvas;
            
            // 清空画布，使用白色背景
            canvas.Clear(SKColors.White);
            
            // 添加干扰线
            using var linePaint = new SKPaint
            {
                Color = SKColors.LightGray,
                StrokeWidth = 1,
                IsAntialias = true
            };
            
            for (int i = 0; i < 5; i++)
            {
                var x1 = _random.Next(width);
                var y1 = _random.Next(height);
                var x2 = _random.Next(width);
                var y2 = _random.Next(height);
                canvas.DrawLine(x1, y1, x2, y2, linePaint);
            }
            
            // 添加干扰点
            for (int i = 0; i < 80; i++)
            {
                var x = _random.Next(width);
                var y = _random.Next(height);
                canvas.DrawPoint(x, y, new SKPaint { Color = SKColor.Parse(GetRandomLightColor()) });
            }
            
            // 绘制验证码文本
            using var textPaint = new SKPaint
            {
                Color = SKColors.DarkBlue,
                IsAntialias = true,
                TextSize = 24,

                Typeface = SKTypeface.FromFile(Path.Combine(AppContext.BaseDirectory, "Config", "simsun.ttf"))
            };
            
            // 计算每个字符的绘制位置
            float charWidth = width / (code.Length + 1);
            for (int i = 0; i < code.Length; i++)
            {
                var charX = (i + 1) * charWidth - 10;
                var charY = height / 2 + 8;
                
                // 随机旋转角度
                canvas.Save();
                canvas.RotateDegrees(_random.Next(-20, 20), charX, charY);
                
                // 随机颜色
                textPaint.Color = SKColor.Parse(GetRandomColor());
                
                canvas.DrawText(code[i].ToString(), charX, charY, textPaint);
                canvas.Restore();
            }
            
            // 将画布转换为PNG格式
            using var image = surface.Snapshot();
            using var data = image.Encode(SKEncodedImageFormat.Png, 100);
            return data.ToArray();
        }
        
        /// <summary>
        /// 获取随机颜色
        /// </summary>
        private string GetRandomColor()
        {
            var colors = new[]
            {
                "#1859E8", "#D61818", "#088C08", "#8C08B5", "#F75000", "#0779AC"
            };
            return colors[_random.Next(colors.Length)];
        }
        
        /// <summary>
        /// 获取随机浅色
        /// </summary>
        private string GetRandomLightColor()
        {
            var colors = new[]
            {
                "#E6E6FA", "#F0FFFF", "#F5F5DC", "#F0F8FF", "#F8F8FF", "#FFF0F5"
            };
            return colors[_random.Next(colors.Length)];
        }
        
        #endregion

        /// <summary>
        /// 将Menu实体转换为AccountMenus DTO
        /// </summary>
        private List<AccountMenus> ConvertToAccountMenus(List<Menu> menus)
        {
            var result = new List<AccountMenus>();

            foreach (var menu in menus)
            {
                var accountMenu = new AccountMenus
                {
                    id = menu.Id.ToString(),
                    path = menu.Path,
                    name = menu.Name,
                    component = menu.Component,
                    redirect = menu.Redirect,
                    meta = new MenuMeta
                    {
                        title = menu.Name,
                        icon = menu.Icon,
                        isExt = menu.IsExt,
                        extOpenMode = menu.ExtOpenMode,
                        type = menu.Type,
                        orderNo = menu.OrderNo,
                        show = menu.Show,
                        activeMenu = menu.ActiveMenu,
                        status = menu.Status,
                        keepAlive = menu.KeepAlive
                    }
                };

                if (menu.Children != null && menu.Children.Any())
                {
                    accountMenu.children = ConvertToAccountMenus(menu.Children);
                }

                result.Add(accountMenu);
            }

            return result;
        }
    }
} 